﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using __ts.Core.Session;
using __ts.Core.Api;

/*
 *  author: able
 *  @2012/2/21 16:03:30
 * 
 */
namespace __ts.Core.Service.IdleChecher
{
    /// <summary>
    /// 
    /// </summary>
    public class IndexedIdleChecker : IdleChecker
    {
        private static int MAX_IDLE_TIME_IN_SEC = 60 * 60; // 1 hour max idle

    private static long MAX_IDLE_TIME_IN_MS = MAX_IDLE_TIME_IN_SEC * 1000L; // 1 hour max idle

    private static ILog LOG = LogManager.GetLogger(typeof(IndexedIdleChecker));

    //private static AttributeKey<Integer> READ_IDLE_INDEX = AttributeKey.createKey(Integer.class,"idle.read.index");
    //private static AttributeKey<Integer> WRITE_IDLE_INDEX = AttributeKey.createKey(Integer.class,"idle.write.index");

    private long lastCheckTime = 0L;

    //@SuppressWarnings("unchecked")
    //private Set<AbstractIoSession>[] readIdleSessionIndex = new Set[MAX_IDLE_TIME_IN_SEC];

    //@SuppressWarnings("unchecked")
    //private Set<AbstractIoSession>[] writeIdleSessionIndex = new Set[MAX_IDLE_TIME_IN_SEC];

    /**
     * {@inheritDoc}
     */
    public void sessionRead(AbstractIoSession session, long timeInMs) {
        //LOG.Debug("session read event, compute idle index of session {}", session);

        // remove from the old index position
        //Integer oldIndex = session.getAttribute(READ_IDLE_INDEX);
        //if (oldIndex != null && readIdleSessionIndex[oldIndex] != null) {
        //    LOG.debug("remove for old index {}", oldIndex);
        //    readIdleSessionIndex[oldIndex].remove(session);
        //}

        //long idleTimeInMs = session.getConfig().getIdleTimeInMillis(IdleStatus.READ_IDLE);
        //// is idle enabled ?
        //if (idleTimeInMs <= 0L) {
        //    LOG.debug("no read idle configuration");
        //} else {
        //    int nextIdleTimeInSeconds = (int) ((timeInMs + idleTimeInMs) / 1000L) + 1;
        //    int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
        //    if (readIdleSessionIndex[index] == null) {
        //        readIdleSessionIndex[index] = new HashSet<AbstractIoSession>();
        //    }

        //    LOG.debug("marking session {} idle for index {}", session, index);
        //    readIdleSessionIndex[index].add(session);
        //    session.setAttribute(READ_IDLE_INDEX, index);
        //}
    }

    /**
     * {@inheritDoc}
     */
    public void sessionWritten(AbstractIoSession session, long timeInMs) {
        //LOG.debug("session write event, compute idle index of session {}", session);

        //// remove from the old index position
        //Integer oldIndex = session.getAttribute(WRITE_IDLE_INDEX);
        //if (oldIndex != null && writeIdleSessionIndex[oldIndex] != null) {
        //    LOG.debug("remove for old index {}", oldIndex);
        //    writeIdleSessionIndex[oldIndex].remove(session);
        //}

        //long idleTimeInMs = session.getConfig().getIdleTimeInMillis(IdleStatus.WRITE_IDLE);
        //// is idle enabled ?
        //if (idleTimeInMs <= 0L) {
        //    LOG.debug("no write idle configuration");
        //} else {
        //    int nextIdleTimeInSeconds = (int) ((timeInMs + idleTimeInMs) / 1000L) + 1;
        //    int index = nextIdleTimeInSeconds % MAX_IDLE_TIME_IN_SEC;
        //    if (writeIdleSessionIndex[index] == null) {
        //        writeIdleSessionIndex[index] = new HashSet<AbstractIoSession>();
        //    }

        //    writeIdleSessionIndex[index].add(session);
        //    session.setAttribute(WRITE_IDLE_INDEX, index);
        //}
    }

    /**
     * {@inheritDoc}
     */
    public int processIdleSession(long time) {
        int counter = 0;
        //long delta = time - lastCheckTime;

        //if (LOG.isDebugEnabled()) {
        //    LOG.debug("checking idle time, last = {}, now = {}, delta = {}",
        //            new Object[] { lastCheckTime, time, delta });
        //}

        //if (delta < 1000) {
        //    LOG.debug("not a second between the last checks, abort");
        //    return 0;
        //}

        //int startIdx = ((int) (Math.max(lastCheckTime, time - MAX_IDLE_TIME_IN_MS + 1) / 1000L)) % MAX_IDLE_TIME_IN_SEC;
        //int endIdx = ((int) (time / 1000L)) % MAX_IDLE_TIME_IN_SEC;

        //LOG.debug("scaning from index {} to index {}", startIdx, endIdx);

        //int index = startIdx;
        //do {
        //    LOG.debug("scanning index {}", index);
        //    // look at the read idle index
        //    counter += processIndex(readIdleSessionIndex, index, IdleStatus.READ_IDLE);
        //    counter += processIndex(writeIdleSessionIndex, index, IdleStatus.WRITE_IDLE);

        //    index = (index + 1) % MAX_IDLE_TIME_IN_SEC;
        //} while (index != endIdx);

        //// save last check time for next call
        //lastCheckTime = time;
        //LOG.debug("detected {} idleing sessions", counter);
        return counter;
    }

    private int processIndex(HashSet<AbstractIoSession>[] indexByTime, int position, IdleStatus status) {
        HashSet<AbstractIoSession> sessions = indexByTime[position];
        if (sessions == null) {
            return 0;
        }

        int counter = 0;

        //foreach (AbstractIoSession idleSession in sessions) {
        //    idleSession.setAttribute(status == IdleStatus.READ_IDLE ? READ_IDLE_INDEX : WRITE_IDLE_INDEX, null);
        //    // check if idle detection wasn't disabled since the index update
        //    if (idleSession.getConfig().getIdleTimeInMillis(status) > 0) {
        //        idleSession.processSessionIdle(status);
        //    }
        //    counter++;
        //}
        //// clear the processed index entry 
        //indexByTime[position] = null;
        return counter;
    }
    }
}